#include "jsapi.h"
#include "js-engine.h"
#include "desktopClasses.h"
#include "basicElementClass.h"
#include "mainview-parser.h"
#include <string.h>

static JSBool checkbox_new(JSContext *cx, JSObject *obj, uintN argc, jsval *args, jsval *rval);
static JSBool checkbox_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);

static JSFunctionSpec checkbox_methods[] = {
    {NULL, NULL, 0, 0, 0}
};

JSClass checkboxClass =
    { "checkbox", JSCLASS_HAS_PRIVATE,
      JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, checkbox_SetProperty, 
      JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
      JSCLASS_NO_OPTIONAL_MEMBERS
    };

struct property_parser checkbox_parser[] = {
    /* from basicElement */
    {"cursor", set_property_string_value},
    {"dropTarget", set_property_boolean_value},
    {"enabled", set_property_boolean_value},
    {"height", set_property_integer_value},
    {"hitTest", set_property_string_value},
    {"mask", set_property_string_value},
    {"name", set_property_string_value},
    {"offsetHeight", set_property_integer_value},
    {"offsetWidth", set_property_integer_value},
    {"offsetX", set_property_integer_value},
    {"offsetY", set_property_integer_value},
    {"opacity", set_property_integer_value},
    {"pinX", set_property_integer_value},
    {"pinY", set_property_integer_value},
    {"rotation", set_property_float_value},
    {"tagName", set_property_string_value},
    {"tooltip", set_property_string_value},
    {"width", set_property_integer_value},
    {"visible", set_property_boolean_value},
    {"x", set_property_integer_value},
    {"y", set_property_integer_value},
		
    {"image", set_property_string_value},
    {"checkedDisabledImage", set_property_string_value},
    {"checkedDownImage", set_property_string_value},
    {"checkedOverImage", set_property_string_value},
    {"checkedImage", set_property_string_value},
    {"disabledImage", set_property_string_value},
    {"downImage", set_property_string_value},
    {"overImage", set_property_string_value},
    {"value", set_property_boolean_value},
		
    {ONCLICK, set_property_function_value},
    {ONRCLICK, set_property_function_value},
    {ONDBLCLICK, set_property_function_value},
    {ONRDBLCLICK, set_property_function_value},
    {"ondragdrop", set_property_function_value},
    {"ondragover", set_property_function_value},
    {ONFOCUSIN, set_property_function_value},
    {ONFOCUSOUT, set_property_function_value},
    {ONKEYDOWN, set_property_function_value},
    {ONKEYPRESS, set_property_function_value},
    {ONKEYUP, set_property_function_value},
    {ONMOUSEDOWN, set_property_function_value},
    {ONMOUSEMOVE, set_property_function_value},
    {ONMOUSEOUT, set_property_function_value},
    {ONMOUSEOVER, set_property_function_value},
    {ONMOUSEUP, set_property_function_value},
    {ONMOUSEWHEEL, set_property_function_value},
    {NULL, NULL},
};

static JSBool checkbox_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
    desktop_element *element = JS_GetPrivate(cx, obj);
    if(JSVAL_IS_STRING(id) && strcmp(JS_GetStringBytes(JS_ValueToString(cx, id)), ONCHANGE) == 0){
	desktop_element_call_handler(element, ONCHANGE);
    }
    if(element->view){
	gtk_widget_queue_draw(element->view);
    }
    return JS_TRUE;
}

static JSBool checkbox_new(JSContext *cx, JSObject *obj, uintN argc, jsval *args, jsval *rval)
{
    return JS_TRUE;
}

JSObject *checkboxClass_init(js_engine *engine, JSObject *parent)
{
    JSObject *proto = NULL;
    proto = JS_InitClass(engine->cx, engine->glob, parent,
			 &checkboxClass, checkbox_new,
			 0,NULL,NULL,NULL,NULL);
    g_return_val_if_fail(proto, FALSE);
    g_return_val_if_fail(JS_DefineFunctions(engine->cx, proto, checkbox_methods), FALSE);
    return proto;
}

static gboolean checkbox_button_event_cb(GtkWidget *widget, GdkEventButton *event, gpointer ptr)
{
    desktop_element *element = (desktop_element *)ptr;
    switch (event->button){
    case 1:{
	switch(event->type){
	case GDK_BUTTON_RELEASE:{
	    jsval value, newValue = JSVAL_TRUE;
	    desktop_element_call_handler(element, ONCLICK);
	    JS_GetProperty(element->engine->cx, element->jsobj, "value", &value);
	    if(JSVAL_IS_BOOLEAN(value) && JSVAL_TO_BOOLEAN(value)){
		newValue = JSVAL_FALSE;
	    }
	    JS_SetProperty(element->engine->cx, element->jsobj, "value", &newValue);
	}
	case GDK_2BUTTON_PRESS:
	    desktop_element_call_handler(element, ONDBLCLICK);
	    break;
	default:
	    break;
	}
	break;
    }
    case 3:{
	switch(event->type){
	case GDK_BUTTON_RELEASE:
	    desktop_element_call_handler(element, ONRCLICK);
	    break;
	case GDK_2BUTTON_PRESS:
	    desktop_element_call_handler(element, ONRDBLCLICK);
	    break;
	default:
	    break;
	}
	break;
    }
    }
    return FALSE;
}

gboolean draw_checkbox(GtkWidget *widget, GdkEvent *event, gpointer ptr)
{
    desktop_element *element = (desktop_element *)ptr;
    GdkPixbuf *image_buf = NULL;
    cairo_t *cr;
    jsval image, checkedDisabledImage, checkedDownImage,
	checkedOverImage, checkedImage, disabledImage, downImage,
	overImage, value, x, y, opacity, enabled, caption;
    gboolean checked = FALSE, isDown = FALSE, isEnable = TRUE;
    gchar *src_path = NULL;
    GError *err = NULL;
    gdouble x_pos = 0, y_pos = 0, opacity_ratio = 1;
    guint imgWidth = 0, imgHeight = 0;

    JS_GetProperty(element->engine->cx, element->jsobj, "x", &x);
    JS_GetProperty(element->engine->cx, element->jsobj, "y", &y);
    JS_GetProperty(element->engine->cx, element->jsobj, "opacity", &opacity);
    JS_GetProperty(element->engine->cx, element->jsobj, "enabled", &enabled);
    JS_GetProperty(element->engine->cx, element->jsobj, "caption", &caption);
    JS_GetProperty(element->engine->cx, element->jsobj, "image", &image);
    JS_GetProperty(element->engine->cx, element->jsobj, "disabledImage", &disabledImage);

    JS_GetProperty(element->engine->cx, element->jsobj, "checkedImage", &checkedImage);
    JS_GetProperty(element->engine->cx, element->jsobj, "checkedDisabledImage", &checkedDisabledImage);

    JS_GetProperty(element->engine->cx, element->jsobj, "downImage", &downImage);
    JS_GetProperty(element->engine->cx, element->jsobj, "checkedDownImage", &checkedDownImage);

    JS_GetProperty(element->engine->cx, element->jsobj, "overImage", &overImage);
    JS_GetProperty(element->engine->cx, element->jsobj, "checkedOverImage", &checkedOverImage);

    JS_GetProperty(element->engine->cx, element->jsobj, "value", &value);

    cr = gdk_cairo_create(widget->window);
    if(JSVAL_IS_BOOLEAN(value) && JSVAL_TO_BOOLEAN(value)){
	checked = TRUE;
    }

    if(JSVAL_IS_BOOLEAN(enabled) && JSVAL_TO_BOOLEAN(enabled) == JS_FALSE){
	isEnable = FALSE;
    }
    
    if(checked){
	if(isEnable){
	    if(JSVAL_IS_STRING(checkedImage)){
		src_path = trans_unix_path_new(JS_GetStringBytes(JSVAL_TO_STRING(checkedImage)));
	    }
	}else{
	    if(JSVAL_IS_STRING(checkedDisabledImage)){
		src_path = trans_unix_path_new(JS_GetStringBytes(JSVAL_TO_STRING(checkedDisabledImage)));
	    }
	}
    }else{
	if(isEnable){
	    if(JSVAL_IS_STRING(image)){
		src_path = trans_unix_path_new(JS_GetStringBytes(JSVAL_TO_STRING(image)));
	    }
	}else{
	    if(JSVAL_IS_STRING(disabledImage)){
		src_path = trans_unix_path_new(JS_GetStringBytes(JSVAL_TO_STRING(disabledImage)));
	    }
	}
    }
    
    if(src_path){
	image_buf = gdk_pixbuf_new_from_file(src_path, &err);
	g_free(src_path);
    }
    imgWidth = gdk_pixbuf_get_width(image_buf);
    imgHeight = gdk_pixbuf_get_height(image_buf);

    if (JSVAL_IS_NUMBER(x))
	JS_ValueToNumber(element->engine->cx, x, &x_pos);
    if (JSVAL_IS_NUMBER(y))
	JS_ValueToNumber(element->engine->cx, y, &y_pos);
    if (JSVAL_IS_INT(opacity)) {
        int value= JSVAL_TO_INT(opacity);
        opacity_ratio = (gdouble)value/255;
    }

    if (JSVAL_IS_STRING(caption)) {
	gchar *caption_str = JS_GetStringBytes(JSVAL_TO_STRING(caption));
	PangoLayout *layout = pango_cairo_create_layout(cr);
	PangoAttrList *list = pango_attr_list_new();
	PangoAttribute *attr;
	PangoRectangle rect;
	gdouble text_width, text_height;

	attr = pango_attr_size_new(DEFAULT_FONT_SIZE * PANGO_SCALE);
	attr->start_index = 0;
	attr->end_index = -1;
	pango_attr_list_insert(list, attr);

	attr = pango_attr_family_new("Sans");
	attr->start_index = 0;
	attr->end_index = -1;
	pango_attr_list_insert(list, attr);

	pango_layout_set_text(layout, caption_str, strlen(caption_str));
	pango_layout_set_attributes(layout, list);
	pango_layout_get_extents(layout, &rect, NULL);
	text_width = rect.width/PANGO_SCALE;
	text_height = rect.height/PANGO_SCALE;

	cairo_move_to(cr, x_pos+imgWidth, y_pos);
	pango_cairo_show_layout(cr, layout);
	gtk_widget_set_size_request(element->view, imgWidth+(guint)text_width, imgHeight);	
    }else{
	gtk_widget_set_size_request(element->view, imgWidth, imgHeight);
    }
    gdk_cairo_set_source_pixbuf(cr, image_buf, x_pos, y_pos);
    cairo_paint_with_alpha(cr, opacity_ratio);

    cairo_destroy(cr);
    return FALSE;
}

void desktop_element_set_view_checkbox(js_engine *engine, desktop_element *element)
{
    element->view = gtk_event_box_new();
    gtk_event_box_set_visible_window(GTK_EVENT_BOX(element->view), FALSE);
    g_signal_connect(element->view, "expose-event",
    		     G_CALLBACK(draw_checkbox), element);
    g_signal_connect(element->view, "button-press-event",
		     G_CALLBACK(checkbox_button_event_cb), element);
    g_signal_connect(element->view, "button-release-event",
		     G_CALLBACK(checkbox_button_event_cb), element);

}
